/*
 * radio.h
 *
 *  Created on: 24-Jan-2009
 *      Author: Neil MacMillan
 *
 *  References:
 *    Ball, Brennen.  DIYEmbedded Tutorials.  http://www.diyembedded.com/
 *    Engelke, Stefan.  AVR-Lib/nRF24L01.  http://www.tinkerer.eu/AVRLib/nRF24L01
 *    Nordic Semiconductor.  nRF24L01 Product Specification 2.0.  http://www.nordicsemi.no/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf
 *
 *    Most of the hard work for this was done by [Engelke].
 */

#ifndef RADIO_H_
#define RADIO_H_

#include <stddef.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "util/delay.h"
#include "nRF24L01.h"
#include "spi.h"

typedef enum _radio_pipe {
	RADIO_PIPE_0 = 0,
	RADIO_PIPE_1 = 1,
	RADIO_PIPE_2 = 2,
	RADIO_PIPE_3 = 3,
	RADIO_PIPE_4 = 4,
	RADIO_PIPE_5 = 5,
	RADIO_PIPE_EMPTY = 7,	// FIFO is empty when pipe number bits in status register are 0b111.
} RADIO_PIPE;

typedef enum _radio_tx_power {
	RADIO_LOWEST_POWER = 0,		// -18 dBm (about 16 uW)
	RADIO_LOW_POWER = 1,		// -12 dBm (about 63 uW)
	RADIO_HIGH_POWER = 2,		// -6 dBm (about 251 uW)
	RADIO_HIGHEST_POWER = 3,	// 0 dBm (1 mW)
} RADIO_TX_POWER;

typedef enum _radio_dr {
	RADIO_1MBPS = 0,		// that's Mbps, not MBps.
	RADIO_2MBPS = 1,
} RADIO_DATA_RATE;

typedef enum _radio_receive {
	RADIO_RX_INVALID_ARGS,		// one of the arguments to Radio_Receive was invalid
	RADIO_RX_TRANSMITTING,		// the radio was transmitting
	RADIO_RX_FIFO_EMPTY,		// there aren't any packets in the Rx FIFO
	RADIO_RX_SUCCESS,			// the read operation succeeded
} RADIO_RX_STATUS;

void Radio_Init();

/**
 * Configure one of the radio's six Rx pipes.
 * \param pipe The pipe to configure.
 * \param address The 1- or 5-byte address to give the pipe.  For pipes 0 and 1 all five bytes can be different, but
 * 		pipes 2-5 share the four most significant bytes of pipe 1's address.  The LSB of each pipe's address must be unique.
 * 		For example:
 * 				Pipe 0: 0x0123456789
 * 				Pipe 1:	0x9876543210
 * 				Pipe 2: 0x98765432AB
 * 				Pipe 3: 0x98765432BC
 * 				Pipe 4: 0x98765432CD
 * 				Pipe 5: 0x98765432DE
 * 		If pipe 0 or 1 is being configured, then address must be a 5-byte array.  If the other four pipes are being configured,
 * 		then the first byte of address is used as the LSB of the pipe's address (i.e. you only pass a 1-byte address, with the
 * 		four MSBytes written to pipe 1's address left implied).  For example, this will set the first four pipe addresses above:
 * 				uint8_t address[5] = {0x01, 0x23, 0x45, 0x67, 0x89};
 * 				Radio_Configure_Rx_Pipe(RADIO_PIPE_0, address, 1, 32, 1);
 * 				address = {0x98, 0x76, 0x54, 0x32, 0x10};
 * 				Radio_Configure_Rx_Pipe(RADIO_PIPE_1, address, 1, 32, 1);
 * 				address[0] = 0xAB;
 * 				Radio_Configure_Rx_Pipe(RADIO_PIPE_2, address, 1, 32, 1);
 * 				address[0] = 0xBC;
 * 				Radio_Configure_Rx_Pipe(RADIO_PIPE_3, address, 1, 32, 1);
 * 				...
 *
 * \param use_aa If this resolves to true, then the pipe will be configured to use Enhanced Shockburst (auto-ack); otherwise
 * 		it will not use Enhanced Shockburst.  For a radio to use Enhanced Shockburst while transmitting, auto-ack must be
 * 		enabled on Rx pipe 0.
 * \param payload_width The width of the payload for this pipe, in bytes (valid values are 1-32).  This will be set to 0
 * 		if the pipe is being disabled.
 * \param enable If this resolves to true, then the pipe will be enabled; otherwise it will be disabled.  Pipe 0 must be enabled
 * 		on the transmitter for auto-ack packets to be received.
 */
void Radio_Configure_Rx(RADIO_PIPE pipe, uint8_t* address, uint8_t use_aa, uint8_t payload_width, uint8_t enable);

/**
 * Get the payload size of the given pipe in bytes.
 */
uint8_t Radio_Get_Pipe_Width(RADIO_PIPE pipe);

/**
 * Configure the radio transmitter.
 * \param address The 5-byte address that packets will be addressed to.
 * \param dr The transmitter's data rate (1 Mbps or 2 Mbps).
 * \param power The transmitter's power output.
 */
void Radio_Configure_Tx(uint8_t* address, RADIO_DATA_RATE dr, RADIO_TX_POWER power);

/**
 * Set the radio transmitter's address.
 * \param The 5-byte address that packets will be sent to.
 */
void Radio_Set_Tx_Addr(uint8_t* address);

/**
 * Transmit some data to the address specified in the last call to Radio_Set_Tx_Addr.  The practical maximum transmission
 * rate is a little less than 300 packets/second, assuming 32 byte packets with low packet loss at 2 Mbps.
 * \param payload A contiguous memory block of data to transmit.
 * \param len The length of the payload.  This must match the receiver's pipe length.  Max 32 bytes.
 * \param block If this resolves to true, then the function will not return until the transmission has been
 * 		acknowledged.  Otherwise, the function will return as soon as the data are sent to the radio.  The
 * 		radio can't send or receive other packets while it's transmitting, but you can still queue up to
 * 		2 more packets.
 * \return 1 if the packet was transmitted successfully, 0 if it was not.
 */
uint8_t Radio_Transmit(void* payload, uint8_t len, uint8_t block);

/**
 * Copy a received packet from the radio Rx FIFO into the supplied buffer.  This function reads the data
 * 		from the radio.  It does not currently handle multiple queued packets.
 * \param buffer The packet will be copied to the memory at this pointer.
 * \param len The length of buffer, in bytes.
 * \return The result of the operation (see enum RADIO_RX_STATUS).
 */
RADIO_RX_STATUS Radio_Receive(void* buffer, uint8_t len, uint8_t block);

#endif /* RADIO_H_ */
